Defining Custom Interfaces

Now that you better understand the overall role of interface types, let’s see an example of defining and implementing custom interfaces. To begin, create a brand-new Console Application named CustomInterface. Using the Project ? Add Existing Item menu option, insert the file(s) containing your shape type definitions (Shapes.cs in the book’s solution code) created back in Chapter 6 during the Shapes example. Once you have done so, rename the namespace that defines your shape-centric types to CustomInterface (simply to avoid having to import namespace definitions in your new project):

namespace CustomInterface
{
    // Your shape types defined here...
}

Now, insert a new interface into your project named IPointy using the Project ? Add New Item menu option, as shown in Figure 9-1.

Figure 9-1

Figure 9-1. Interfaces, like classes, can be defined in any *.cs file

At a syntactic level, an interface is defined using the C# interface keyword. Unlike a class, interfaces never specify a base class (not even System.Object; however, as you will see later in this chapter, an interface can specify base interfaces). Moreover, the members of an interface never specify an access modifier (as all interface members are implicitly public and abstract). To get the ball rolling, here is a custom interface defined in C#:

// This interface defines the behavior of "having points."
public interface IPointy
{
    // Implicitly public and abstract.
    byte GetNumberOfPoints();
}

Remember that when you define interface members, you do not define an implementation scope for the member in question. Interfaces are pure protocol, and therefore never define an implementation (that is up to the supporting class or structure). Therefore, the following version of IPointy would result in various compiler errors:

// Ack! Errors abound!
public interface IPointy
{
    // Error! Interfaces cannot have fields!
    public int numbOfPoints;

    // Error! Interfaces do not have constructors!
    public IPointy() { numbOfPoints = 0;};

    // Error! Interfaces don't provide an implementation of members!
    byte GetNumberOfPoints() { return numbOfPoints; }
}

In any case, this initial IPointy interface defines a single method. However, .NET interface types are also able to define any number of property prototypes. For example, you could create the IPointy interface to use a read-only property rather than a traditional accessor method:

// The pointy behavior as a read-only property.
public interface IPointy
{
    // A read-write property in an interface would look like:
    // retType PropName { get; set; }
    // while a write-only property in an interface would be:
    // retType PropName { set; }

    byte Points { get; }
}

Note Interface types can also contain event (see Chapter 11) and indexer (see Chapter 12) definitions

Interface types are quite useless on their own, as they are nothing more than a named collection of abstract members. For example, you can’t allocate interface types as you would a class or structure:

// Ack! Illegal to allocate interface types.
static void Main(string[] args)
{
    IPointy p = new IPointy(); // Compiler error!
}

Interfaces do not bring much to the table until they are implemented by a class or structure. Here, IPointy is an interface that expresses the behavior of “having points.” The idea is simple: some classes in the shapes hierarchy have points (such as the Hexagon), while others (such as the Circle) do not.